package cn.org.xwb.main.service.impl;

import cn.org.xwb.main.constants.MailConstant;
import cn.org.xwb.main.constants.ResponseConstant;
import cn.org.xwb.main.dto.BaseRespResult;
import cn.org.xwb.main.dto.ClientErrorRespResult;
import cn.org.xwb.main.dto.ServerErrorRespResult;
import cn.org.xwb.main.dto.SuccessRespResult;
import cn.org.xwb.main.prop.MailProp;
import cn.org.xwb.main.service.LoginService;
import cn.org.xwb.main.utils.FileUtil;
import cn.org.xwb.main.utils.MailUtil;
import cn.org.xwb.main.utils.RandomUtil;
import cn.org.xwb.main.utils.RedisUtil;
import cn.org.xwb.main.vo.LoginInfoByMailVo;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Objects;

@Service
@Log4j2
public class LoginServiceImpl implements LoginService {

    /**
     * redis 工具类对象
     */
    @Autowired
    private RedisUtil redisUtil;

    /**
     * 邮件配置属性绑定对象
     */
    @Autowired
    private MailProp mailProp;

    /**
     * 邮件工具类
     */
    @Autowired
    private MailUtil mailUtil;

    /**
     * 发送邮箱验证码。
     * 用户通过输入的邮箱获取登录时使用的验证码。
     *
     * @param mail 邮箱
     * @return 响应结果对象，其中响应数据：true-发送成功；false-发送失败
     */
    @Override
    public BaseRespResult<Object> sendMailCode(String mail) {
        try {
            // 验证是否可以获取邮箱验证码
            // 尝试从 redis 中获取之前获取过的邮箱验证码
            String codeAgain = redisUtil.getStrVal(MailConstant.getLoginMailCodeAgainRedisKey(mail));
            // 如果之前获取过，且还在再次获取邮箱验证码的等待时间内，直接返回响应结果对象
            if (Objects.nonNull(codeAgain)) {
                log.error("向 {} 发送邮箱验证码失败，原因：客户端频繁获取验证码", mail);
                return ClientErrorRespResult.clientErrorRespResult(ResponseConstant.MAIL_CODE_GET_FREQUENTLY);
            }
            // 得到 HTML 格式的邮件内容模板
            String mailContentHTML = FileUtil.readFileContentByChar(
                    FileUtil.getClassPathFileAbsolute(mailProp.getDefaultContentHtmlPath())
            );
            // 生成 6 位随机数字验证码
            String code = RandomUtil.genRandNumStr(mailProp.getCodeLen());
            // 将生成的验证码放入 HTML 格式的邮件内容模板中
            mailContentHTML = mailContentHTML.replace(mailProp.getDefaultContentHtmlCodeTemplate(), code);
            // 将验证码有效时间放入 HTML 格式的邮件内容模板中
            mailContentHTML = mailContentHTML.replace(
                    mailProp.getDefaultContentHtmlExpireTemplate(),
                    String.valueOf(mailProp.getCodeExpire() / 60)
            );
            // 生成发送邮件所需的相关信息，发送邮件
            Boolean mailSendResult = mailUtil.sendHTMLMessage(mailUtil.genMailSendInfoDto(mail, mailContentHTML));
            // 发送邮件失败响应
            if (!mailSendResult) {
                log.error("向 {} 发送邮箱验证码失败，原因：服务端发送邮件时发生错误", mail);
                return ServerErrorRespResult.serverErrorRespResult(ResponseConstant.MAIL_CODE_SEND_ERROR);
            }
            // 将生成的验证码保存到 redis 中
            redisUtil.setStrVal(
                    MailConstant.LOGIN_MAIL_CODE_REDIS_KEY.formatted(mail),
                    code,
                    mailProp.getCodeExpire()
            );
            // 保存由于验证是否可以再次获取邮箱验证码的键值
            redisUtil.setStrVal(
                    MailConstant.LOGIN_MAIL_CODE_AGAIN_REDIS_KEY.formatted(mail),
                    code,
                    mailProp.getCodeAgain()
            );
            // 发送邮件成功响应
            log.info("向 {} 发送邮箱验证码成功", mail);
            return SuccessRespResult.successRespResult(ResponseConstant.MAIL_CODE_SEND_SUCCESS, true);
        } catch (Exception e) {
            log.error("向 {} 发送邮箱验证码失败，原因：服务端发生错误，\n错误信息：{}，\nerror：{}", mail, e.getMessage(), e);
            return ServerErrorRespResult.serverErrorRespResult(ResponseConstant.SERVER_ERROR);
        }
    }

    /**
     * 用户通过电子邮箱进行登录
     *
     * @param loginInfo 用户登录信息
     * @return 响应结果对象
     */
    @Override
    public BaseRespResult<Object> loginByMail(LoginInfoByMailVo loginInfo) {
        // 用户输入的邮箱和验证码
        String mail = loginInfo.getMail();
        String code = loginInfo.getCode();
        // redis key
        String redisKey = MailConstant.getLoginMailCodeRedisKey(mail);
        // redis 中的验证码失效
        if (redisUtil.keyValueIsExists(redisKey)) {
            log.info("用户 {} 获取的验证码 {} 失效", mail, code);
            return ClientErrorRespResult.clientErrorRespResult(ResponseConstant.MAIL_CODE_EXCEED_THE_TIME_LIMIT);
        }
        // 验证码输入错误
        if (redisUtil.keyValueEqual(redisKey, code)) {
            log.info("用户 {} 输入的验证码 {} 错误", mail, code);
            return ClientErrorRespResult.clientErrorRespResult(ResponseConstant.MAIL_CODE_INPUT_ERROR);
        }
//        // 查询账号条件
//        QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<>();
//        // 根据邮箱查询账号
//        userInfoQueryWrapper.eq(UserInfoConstant.COLUMN_NAME_MAIL, userLoginInfoVo.getMail());
//        // 根据邮箱从数据库中查询账号
//        UserInfo userInfo = userInfoMapper.selectOne(userInfoQueryWrapper);
//        // 判断是否存在账号
//        // 如果账号不存在，进行账号注册，生成新账号
//        if (Objects.isNull(userInfo)) {
//            // 生成的新账号信息
//            userInfo = registerNewAccountByMail(userLoginInfoVo.getMail());
//            // 新用户账号信息入库
//            int row = userInfoMapper.insert(userInfo);
//            // 数据库新增用户信息失败，返回失败响应结果对象
//            if (row < 1) {
//                return ServerErrorResponseResult.errorResult(
//                        ResponseResultMessageConstant.LOGIN_ERROR
//                );
//            }
//        }
//        // 修改登录时间
//        modifyUserLoginTime(userInfo);
//        // 用户信息缓存到 redis
//        redisUtil.setStrVal(
//                UserInfoConstant.getUserInfoRedisKey(userInfo.idStr()),
//                userInfo,
//                userInfoProperties.getUserinfoExpire(),
//                TimeUnit.DAYS
//        );
//        // 根据数据库中的用户账号信息转换生成传递给客户端的用户信息
//        UserInfoDto userInfoDto = DtoUtil.generateUserInfoDto(userInfo);
        // 登录成功
        log.info("用户 {} 登录成功，输入的验证码：{}", mail, code);
//        return SuccessRespResult.successRespResult(ResponseConstant.LOGIN_SUCCESS, userInfoDto);
        return SuccessRespResult.successRespResult(ResponseConstant.LOGIN_SUCCESS, true);
    }
}
